package com.agrm.utils;

import com.agrm.model.common.dtos.TreeEntity;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 功能：树工具类
 *
 * @author 千堆雪
 * @version 1.0.0
 * created on 2025/4/19 10:29, last modified on 2025/4/19 10:29
 */
public class TreeUtils {

    //构建树
    public static <T extends TreeEntity<T, ID>, ID extends Serializable> List<T> buildTree(Collection<T> all) {
        //缓存所有节点
        Map<ID, T> cache = all.stream().collect(Collectors.toMap(TreeEntity::getId, t -> t));

        //存储所有根节点
        List<T> roots = new ArrayList<>();

        for (T t : cache.values()) {
            if (t.getParentId() == null) {//若父节点编号为null，则为根节点
                roots.add(t);
            } else {
                ID parentId = t.getParentId();//父节点编号
                T parent = cache.get(parentId);
                if (parent == null) {
                    throw new RuntimeException("无效的父节点编号:" + parentId);
                }
                if (parent.getChildren() == null) {
                    parent.setChildren(new ArrayList<>());
                }
                parent.getChildren().add(t);
                t.setParent(parent);
            }
        }

        return roots;
    }


    //继承链
    public static <T extends TreeEntity<T, ID>, ID extends Serializable> List<T> parents(T t) {
        List<T> list = new ArrayList<>();
        T parent = t.getParent();
        while (parent != null) {
            list.add(0,parent);
            parent = parent.getParent();
        }
        return list;
    }


    public static <T extends TreeEntity<T, ID>, ID extends Serializable> T findById(T root, ID id) {
        return findById(List.of(root), id);
    }

    /**
     * 深度优先，递归搜索
     *
     * @param all  所有待查询节点
     * @param id   目标节点编号
     * @param <T>  节点类型
     * @param <ID> 节点编号类型
     * @return 目标节点
     */
    public static <T extends TreeEntity<T, ID>, ID extends Serializable> T findById(List<T> all, ID id) {
        for (T t : all) {
            if (t.getId().equals(id)) {
                return t;
            }
            if (!CollectionUtils.isEmpty(t.getChildren())) {
                T found = findById(t.getChildren(), id);
                if (found != null) {
                    return found;
                }
            }
        }
        return null;
    }
}
